package org.zjvis.dlt;

import static org.zjvis.dlt.utils.DataLineageUtil.onlySemicolonsOrNewLine;

import com.google.common.collect.Lists;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.zjvis.dlt.data.data_lineage.FieldLineageCanvasInfo;
import org.zjvis.dlt.data.data_lineage.TableLineageCanvasInfo;
import org.zjvis.dlt.data.data_lineage.TotalCanvasInfo;
import org.zjvis.dlt.data.vo.DataLineageRequest;
import org.zjvis.dlt.enums.ApiResultCode;
import org.zjvis.dlt.model.ApiResult;
import org.zjvis.dlt.service.DataLineageService;
import org.zjvis.dlt.service.FieldLineageService;
import org.zjvis.dlt.service.TableLineageService;
import org.zjvis.dp.data.lineage.data.DatabaseConfig;
import org.zjvis.dp.data.lineage.data.GrammarCheckErrorResult;

/**
 * @author zhouyu
 * @create 2023-07-11 11:16
 */
@Api(tags = "数据血缘访问接口")
@RestController
public class DataLineageController {

    @Resource
    TableLineageService tableLineageService;

    @Resource
    FieldLineageService fieldLineageService;

    @Resource
    DataLineageService dataLineageService;

    @PostMapping(value = "/parseAllLineage")
    @ApiOperation(value = "解析表、字段血缘")
    public ApiResult<Object> parseAllLineage(@RequestBody DataLineageRequest dataLineageRequest) {
        DatabaseConfig databaseConfig = new DatabaseConfig();
        BeanUtils.copyProperties(dataLineageRequest.getDatabaseInfo(), databaseConfig);
        try {
            List<TableLineageCanvasInfo> tableLineageCanvasInfos = Lists.newArrayList();
            List<String> lineList = Arrays.stream(dataLineageRequest.getSql().split("\\n"))
                    .collect(Collectors.toList());
            List<String> sqlList = Lists.newArrayList();
            List<Integer> sqlStartStartNumberList = Lists.newArrayList();
            int sqlStartLineNumber = 0;
            for(int i = 0; i < lineList.size(); i++) {
                String lineStr = lineList.get(i);
                for(int j = 0; j < lineStr.length(); j++) {
                    //行中间有分号
                    if(lineStr.charAt(j) == ';') {
                         if(j != lineStr.length() -1) {
                             GrammarCheckErrorResult result = GrammarCheckErrorResult.builder()
                                     .grammarError(Boolean.TRUE)
                                     .lineNumber(i)
                                     .indexOfLine(j)
                                     .errorMessage("lines contain semicolons")
                                     .build();
                             return ApiResult.valueOf(ApiResultCode.GRAMMAR_ERROR, result);
                         } else {
                            //从1开始
                            sqlStartStartNumberList.add(sqlStartLineNumber);
                            sqlList.add(StringUtils.join(lineList.subList(sqlStartLineNumber, i + 1), "\n"));
                            sqlStartLineNumber = i + 1;
                         }
                    }
                }
            }

            //语法检查，
            for(int i = 0; i < sqlList.size(); i++) {
                if(onlySemicolonsOrNewLine(sqlList.get(i))) {
                    continue;
                }
                GrammarCheckErrorResult checkResult = dataLineageService.grammarCheck(
                        dataLineageRequest.getDatabaseInfo().getSqlType(),
                        sqlList.get(i)
                );
                if(checkResult.isGrammarError()) {
                    checkResult.setLineNumber(checkResult.getLineNumber() + sqlStartStartNumberList.get(i));
                    return ApiResult.valueOf(ApiResultCode.GRAMMAR_ERROR, checkResult);
                }
            }

            for (String sqlElement : sqlList) {
                if(onlySemicolonsOrNewLine(sqlElement)) {
                    continue;
                }
                tableLineageCanvasInfos.add(
                        tableLineageService.processTableLineageParser(
                                dataLineageRequest.getDatabaseInfo().getSqlType(),
                                databaseConfig.getDatabaseName(),
                                sqlElement
                        )
                );
            }
            TableLineageCanvasInfo tableLineageCanvasInfo = tableLineageService.mergeTableCanvasInfo(tableLineageCanvasInfos);

            List<FieldLineageCanvasInfo> fieldLineageCanvasInfos = Lists.newArrayList();
            for (String sqlElement : sqlList) {
                if(onlySemicolonsOrNewLine(sqlElement)) {
                    continue;
                }
                fieldLineageCanvasInfos.add(
                        fieldLineageService.processFieldLineageParser(
                                dataLineageRequest.getDatabaseInfo().getSqlType(),
                                databaseConfig,
                                sqlElement
                        )
                );
            }
            FieldLineageCanvasInfo fieldLineageCanvasInfo = fieldLineageService.mergeFieldCanvasInfo(
                    fieldLineageCanvasInfos,
                    databaseConfig,
                    dataLineageRequest.getDatabaseInfo().getSqlType()
            );

            return ApiResult.valueOf(
                    TotalCanvasInfo.builder()
                            .tableLineageCanvasInfo(tableLineageCanvasInfo)
                            .fieldLineageCanvasInfo(fieldLineageCanvasInfo)
                            .build()
            );
        } catch (Exception e) {
            return ApiResult.error(ApiResultCode.SYS_ERROR, e.getMessage());
        }
    }
}
